package com.zhuoyue;

import java.lang.reflect.Field;
import java.util.Timer;
import java.util.TimerTask;

/**
 *
 * 心跳管理
 *
 * 判断连接是否仍然存在，如不存在则不发送。
 *
 * 判断最后一次发送时间和当前时间做对比，是否大于 ClientConfig.heartbeatTimeSeconds
 *
 * @author Created by mr.liang
 */
public class HeartbeatManagement {

    private WriterManagement writerManagement;

    private HeartbeatTask heartbeatTask;

    private ClientConfig clientConfig;

    private ConnectionManagement connectionManagement;

    private Timer timer;


    public HeartbeatManagement(ClientConfig clientConfig, ConnectionManagement connectionManagement, WriterManagement writerManagement) {
        this.clientConfig = clientConfig;
        this.connectionManagement = connectionManagement;
        this.writerManagement = writerManagement;
        this.timer = clientConfig.getTimer();

    }


    synchronized void start(){
        if(heartbeatTask == null){
            heartbeatTask = new HeartbeatTask();
            heartbeatTask.next(clientConfig.getHeartbeatTimeMill());
        }
    }

    class HeartbeatTask extends TimerTask {

        @Override
        public void run() {
            long nextTime ;
            if(connectionManagement.isConnecting()){//由于timer线程只有一条，所以理论上这里会阻塞。
                nextTime = clientConfig.getHeartbeatTimeMill();
            }else{
                long diff = System.currentTimeMillis() - writerManagement.getLastSendTime() + 10;//这个+10因为timer提前触发导致出现diff=9999这种情况，
                if(diff >= clientConfig.getHeartbeatTimeMill()){
                    writerManagement.send(clientConfig.getHeartbeatPacket());
                    nextTime = clientConfig.getHeartbeatTimeMill();
                }else{
                    nextTime = clientConfig.getHeartbeatTimeMill() - diff;
                }
            }
            next(nextTime);
        }

        public void next(long nextTime){
            resetTask();
            timer.schedule(this,nextTime);
        }



        Field stateField = null;
        {
            try {
                stateField = TimerTask.class.getDeclaredField("state");
                stateField.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }

        public void resetTask(){
            try {
                stateField.set(this,0);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }


}
